﻿using System;
using System.Configuration;
using System.Collections.Generic;
using System.ComponentModel;
using System.Xml;
using System.Xml.XPath;

namespace Xml2Yaml
{
    class YamlConfig
    {
        public IDictionary<string, string> Namespaces = new Dictionary<string, string>();
        private IDictionary<string, string> Mapping = new Dictionary<string, string>();
        private List<string> IgnoreList = new List<string>();
        private bool Available = false;
        public bool Initialized
        {
            private set;
            get;
        }

        public YamlConfig(string fileName)
        {
            Initialized = true;
            Available = YamlUtil.IsTrue(ConfigurationManager.AppSettings["userconfig"])
                && LoadConfiguationFile(fileName);
        }

        [DefaultValue(true)]
        public bool DisplayComment
        {
            get;
            private set;
        }


        [DefaultValue("1.2")]
        public string Version
        {
            get;
            private set;
        }

        public IDictionary<string, string> Tags
        {
            get
            {
                return Namespaces;
            }
        }

        private bool LoadConfiguationFile(string fileName)
        {
            if (!string.IsNullOrEmpty(fileName))
            {
                try
                {
                    XPathNavigator nav = XPathNavigatorUtil.LoadFromFile(fileName);
                    XPathNavigator root = XPathNavigatorUtil.SelectSingleNode(nav, "/yaml");
                    if (root == null)
                    {
                        Initialized = false;
                        return false;
                    }

                    Version = XPathNavigatorUtil.ReadNodeStringValue(root, "version");
                    DisplayComment = XPathNavigatorUtil.ReadNodeBooleanValue(root, "comment");

                    foreach (XPathNavigator item in XPathNavigatorUtil.Select(root, "ignore/xpath"))
                    {
                        IgnoreList.Add(XPathNavigatorUtil.ReadNodeStringValue(item));
                    }

                    foreach (XPathNavigator item in XPathNavigatorUtil.Select(root, "mapping/xpath"))
                    {
                        string key = XPathNavigatorUtil.ReadNodeStringValue(item, "@key");
                        string value = XPathNavigatorUtil.ReadNodeStringValue(item, "@value");
                        if (Mapping.ContainsKey(key))
                        {
                            Mapping[key] = value;
                        }
                        else
                        {
                            Mapping.Add(key, value);
                        }
                    }


                    foreach (XPathNavigator item in XPathNavigatorUtil.Select(root, "namespace/add"))
                    {
                        string key = XPathNavigatorUtil.ReadNodeStringValue(item, "@key");
                        string value = XPathNavigatorUtil.ReadNodeStringValue(item, "@value");
                        if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
                        {
                            if (Namespaces.ContainsKey(key))
                            {
                                Namespaces[key] = value;
                            }
                            else
                            {
                                Namespaces.Add(key, value);
                            }
                        }
                    }

                    return true;
                }
                catch (XmlException ex)
                {
                    Console.Error.WriteLine(ex.Message);
                }
            }

            return false;
        }

        /// <summary>
        /// Is Xpath is ignored, not output
        /// </summary>
        /// <param name="xpath"></param>
        /// <returns></returns>
        public bool IsIgnoreXPath(XPathParser parser)
        {
            if (Available && parser != null)
            {
                return parser.QueryWithXPath(IgnoreList);
            }

            return Available;
        }

        /// <summary>
        /// Get XPath Mapping String
        /// </summary>
        /// <param name="xpath"></param>
        /// <returns></returns>
        public string GetMappingFromXPath(XPathParser parser, string localName)
        {
            if (Available && parser != null)
            {
                return parser.QueryWithXPath(Mapping, localName);
            }
            return localName;
        }

        /// <summary>
        /// Get Mapping Namespace
        /// </summary>
        /// <param name="ns"></param>
        /// <returns></returns>
        public string GetNamespaceMapping(string ns, bool tag = true)
        {
            string result = string.Empty;

            if (Available && Namespaces.TryGetValue(ns, out result))
            {
                if (tag)
                {
                    return "!" + result + "!";
                }
                else
                {
                    return result;
                }
            }

            return result;
        }
    }
}
